﻿using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.Serialization;
using Game.Common.Visitor;
using Game.ExtensibleObjects;

namespace Game.Map.Internal
{
    [DataContract(Namespace="game")]
    public class GameMap : IGameMap
    {
        public event EventHandler<MapEventArgs> Dirty;

        [DataMember(Name="GlobalItems", Order=1)]
        public readonly GlobalItemCollection _GlobalItems = new GlobalItemCollection();
        
        [DataMember(Name="Fields", Order=2)]
        public readonly GameFieldCollection _MapFieldCollection;
        
        [DataMember(Name="Width", Order=3)]
        public readonly int _Width;
        
        [DataMember(Name="Height", Order=4)]
        public readonly int _Height;

        RuntimeExtensionCollection _Extensions;

        public GameMap()
        {
        }
        
        internal GameMap(
            int width, 
            int height)
        {
            _Width = width;
            _Height = height;
            _MapFieldCollection = new GameFieldCollection();
            SetupExtensions();
            CreateFields(width, height);
        }

        [OnDeserialized]
        public void OnDeserialized2(StreamingContext c)
        {
            SetupExtensions();
            MapFieldFactory.FireSetupFields(this);
            Factory.CreateViews(this);
        }

        void SetupExtensions()
        {
            _Extensions = new RuntimeExtensionCollection();

            foreach (var f in MapConfig.MapExtensions)
            {
                _Extensions.Add(f.CreateExtension(this));
            }
        }

        public int Width
        {
            get { return _Width; }
        }
        
        public int Height
        {
            get { return _Height; }
        }
        
        public GlobalItemCollection GlobalItems 
        {
            get { return _GlobalItems; }
        }
        
        public GameFieldCollection Fields
        {
            get { return _MapFieldCollection; }
        }

        public ViewCollection Views { get; internal set; }

        public RuntimeExtensionCollection Extensions
        {
            get { return _Extensions; }
        }
       
        public bool IsDirty
        {
            get
            {
                return _MapFieldCollection.Any(field => field.IsDirty);
            }
            set 
            {
                foreach(var field in _MapFieldCollection)
                {
                    field.IsDirty = value;
                }
            }
        }

        public void Accept(IVisitor visitor)
        {
            foreach (var item in _Extensions)
            {
                var element = item as IVisitorElement;
                if (element != null)
                {
                    element.Accept(visitor);
                }
            }

            foreach (var item in _MapFieldCollection)
            {
                var element = item as IVisitorElement;
                Debug.Assert(element != null, "element != null");
                element.Accept(visitor);
            }
        }

        void CreateFields(int width, int height)
        {
            for (double y = 0; y < height; y++)
            {
                for (double x = 0; x < width; x++)
                {
                    var field = MapFieldFactory.CreateField(this, x, y);
                    _MapFieldCollection.Add(field);
                    
                    field.Changed += delegate
                    {
                        if (Dirty != null)
                        {
                            Dirty(this, new MapEventArgs(this));
                        }
                    };
                }
            }
        }

    }
}
